package com.rzy.l_volatile.b;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CountDownLatch;

/**
 该例子演示了，volatile并不能保证原子性
 是因为，每次对volatile变量的读，总是会读取到上一次对该volatile变量写的内容，并不是让线程能时刻“感知”volatile变量的变化。只有在读取volatile
 变量的时候，才会把主存中的值读取到线程的工作内存中。

 volatile为什么不保证原子性？
 volatile之所以不保证原子性，是因为volatile修饰的变量在不同的线程的工作内存中也存在不一致的情况。
 比如：
 线程1                                         线程2
 读取i=1                                       读取i=1
 i++; // i=2                                   i++;    // i=2
 此时没有刷新工作内存(因为此时没有涉及到读取)         存储i=2到主存
 存储2到主存

 所以，关于volatile才有了以下的使用准则
 1. 运算结果并不依赖于变量当前的值，或者能够确保只有单一的线程修改变量的值，而其他的线程只是读取变量的值。
 2. 变量不需要与其他的状态变量共同参与不变约束。
*/
public class App {
	volatile int count = 0;

	static CountDownLatch cd = new CountDownLatch(10);

	void f1() {
		for (int i = 1; i <= 1000; i++) {
			/*
				取出count
				count+1
				赋值给count
			 */
			count++;
		}
		cd.countDown();
	}

	public static void main(String[] args) throws InterruptedException {
		App app = new App();

		List<Thread> list = new ArrayList<>();
		for(int i = 1; i <= 10; i++) {
			Thread th = new Thread(new Runnable() {
				@Override
				public void run() {
					app.f1();
				}
			});
			list.add(th);
		}

		for (Thread th : list) {
			th.start();
		}

		// 这里要阻塞，直到10个线程都执行完毕
		cd.await();
		System.out.println(app.count);

	}
}
